"""
Agent与知识库集成服务
提供创建Agent并自动配置知识库的功能
"""
from typing import Tuple, Optional
import logging
import re

from src.llm.hiagent_app.utils.api_client import HiAgentAPIClient
from src.llm.hiagent_app.config.hiagent_config import HiAgentConfig

logger = logging.getLogger(__name__)


class AgentKnowledgeService:
    """Agent与知识库集成服务"""

    def __init__(self, api_client: Optional[HiAgentAPIClient] = None):
        self.api_client = api_client or HiAgentAPIClient()

    @staticmethod
    def _sanitize_knowledge_name(name: str) -> str:
        """
        清理知识库名称，移除或替换不允许的字符
        知识库名称规则：只允许中文、英文、数字、下划线
        """
        # 移除或替换空格为下划线
        name = name.replace(" ", "_")
        # 移除其他特殊字符，只保留中文、英文、数字、下划线
        name = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9_]', '', name)
        # 如果名称为空，使用默认值
        if not name:
            name = "知识库"
        return name

    def create_agent_with_knowledge(
        self,
        agent_name: str,
        knowledge_name: Optional[str] = None,
        agent_description: Optional[str] = None,
        workspace_id: Optional[str] = None,
        source_agent_id: Optional[str] = None
    ) -> Tuple[str, str]:
        """
        创建Agent并配置知识库（从源智能体复制）

        Args:
            agent_name: Agent名称
            knowledge_name: 知识库名称，如果不提供则使用 {agent_name}_知识库
            agent_description: Agent描述
            workspace_id: 工作空间ID（必填）
            source_agent_id: 源智能体ID（必填，从该智能体复制配置）

        Returns:
            tuple: (agent_id, knowledge_id)

        Raises:
            ValueError: workspace_id 或 source_agent_id 未提供时抛出
            Exception: 创建或配置失败时抛出异常
        """
        # 验证必需参数
        if not workspace_id:
            raise ValueError("workspace_id 是必需参数，不能为空")

        if not source_agent_id:
            raise ValueError("source_agent_id 是必需参数，不能为空")

        ws_id = workspace_id

        if not knowledge_name:
            knowledge_name = f"{agent_name}_知识库"

        # 清理知识库名称，移除不允许的字符
        knowledge_name = self._sanitize_knowledge_name(knowledge_name)

        if not agent_description:
            agent_description = f"智能助手 - {agent_name}"

        logger.info(f"开始从源智能体复制并配置知识库 - Source: {source_agent_id}, Agent: {agent_name}, Knowledge: {knowledge_name}, WorkspaceID: {ws_id}")

        # 步骤1: 从源智能体复制
        agent_id = self._copy_agent(source_agent_id, ws_id)
        logger.info(f"Agent复制成功 - ID: {agent_id}")

        # 更新Agent名称和描述
        self._update_agent_basic_info(agent_id, agent_name, agent_description, ws_id)
        logger.info(f"Agent信息已更新 - Name: {agent_name}")

        try:
            # 步骤2: 获取知识库根目录
            root_directory_id = self._get_root_directory(ws_id)
            logger.info(f"获取到根目录ID: {root_directory_id}")

            # 步骤3: 创建知识库
            knowledge_id = self._create_knowledge(
                knowledge_name,
                f"配套知识库 - {agent_name}",
                root_directory_id,
                ws_id
            )
            logger.info(f"知识库创建成功 - ID: {knowledge_id}")

            # 步骤4: 配置Agent使用知识库
            self._configure_agent_knowledge(agent_id, knowledge_id, agent_name, ws_id)
            logger.info(f"Agent配置成功 - 已关联知识库 {knowledge_id}")

            return agent_id, knowledge_id

        except Exception as e:
            # 出错时清理已创建的资源
            logger.error(f"创建过程失败，开始清理资源: {str(e)}")
            self._cleanup_resources(agent_id, locals().get('knowledge_id'), ws_id)
            raise

    def _create_agent(self, name: str, description: str, workspace_id: str) -> str:
        """创建Agent"""
        try:
            create_app_body = {
                "WorkspaceID": workspace_id,
                "Name": name,
                "AppType": "Chat",
                "Description": description
            }

            response = self.api_client.make_request("CreateApp", create_app_body)
            agent_id = response.get("AppID")

            if not agent_id:
                raise Exception("CreateApp API未返回AppID")

            return agent_id

        except Exception as e:
            logger.error(f"Agent创建失败: {str(e)}")
            raise Exception(f"Agent创建失败: {str(e)}")

    def _copy_agent(self, source_agent_id: str, workspace_id: str) -> str:
        """从现有智能体复制创建新的Agent"""
        try:
            copy_app_body = {
                "FromAppID": source_agent_id,
                "WorkspaceID": workspace_id
            }

            response = self.api_client.make_request("CopyApp", copy_app_body)
            agent_id = response.get("AppID")

            if not agent_id:
                raise Exception("CopyApp API未返回AppID")

            return agent_id

        except Exception as e:
            logger.error(f"Agent复制失败: {str(e)}")
            error_msg = str(e)
            if "部分组件需调整" in error_msg or "需调整、发布" in error_msg:
                raise Exception("源智能体配置不完整，无法复制。请先为源智能体配置模型、提示词等必要组件，并保存草稿配置。")
            else:
                raise Exception(f"Agent复制失败: {error_msg}")

    def _update_agent_basic_info(self, agent_id: str, name: str, description: str, workspace_id: str) -> None:
        """更新Agent的基本信息(名称和描述)"""
        try:
            update_app_body = {
                "WorkspaceID": workspace_id,
                "AppID": agent_id,
                "Name": name,
                "Description": description
            }

            self.api_client.make_request("UpdateApp", update_app_body)

        except Exception as e:
            logger.error(f"Agent信息更新失败: {str(e)}")
            raise Exception(f"Agent信息更新失败: {str(e)}")

    def _get_root_directory(self, workspace_id: str) -> str:
        """获取知识库根目录ID"""
        try:
            directory_tree_response = self.api_client.make_request(
                "GetDatasetDirectoryTree",
                {"WorkspaceID": workspace_id}
            )

            directories = directory_tree_response.get("Directories", [])
            root_directory_id = directories[0]["ID"] if directories else "root"
            return root_directory_id

        except Exception as e:
            logger.warning(f"获取根目录失败，使用默认值: {str(e)}")
            return "root"

    def _create_knowledge(
        self,
        name: str,
        description: str,
        directory_id: str,
        workspace_id: str
    ) -> str:
        """创建知识库"""
        try:
            create_dataset_body = {
                "WorkspaceID": workspace_id,
                "Name": name,
                "Description": description,
                "SpaceType": 1,  # 个人空间
                "Icon": "upload/full/38/82/8c3fc2983b873d3092a9ccd9f6329affea3729c5ec32bb86a0026497cefe",
                "Models": {
                    "EmbedID": HiAgentConfig.DEFAULT_EMBEDDING_MODEL_ID  # 默认embedding模型
                },
                "DirectoryID": directory_id,
                "IndexingTechnique": 0,  # 向量化模式: 0=普通（文档上传时配置）
                "RetrievalSearchMethod": 0  # 检索方式: 默认
            }

            response = self.api_client.make_request("CreateDataset", create_dataset_body)
            knowledge_id = response.get("Id")

            if not knowledge_id:
                raise Exception("CreateDataset API未返回Id")

            return knowledge_id

        except Exception as e:
            logger.error(f"知识库创建失败: {str(e)}")
            raise Exception(f"知识库创建失败: {str(e)}")

    def _configure_agent_knowledge(
        self,
        agent_id: str,
        knowledge_id: str,
        agent_name: str,
        workspace_id: str
    ) -> None:
        """配置Agent使用知识库（保留已有配置，替换知识库引用）"""
        try:
            # 先获取当前Agent的配置（从复制的智能体继承的配置）
            get_draft_body = {
                "WorkspaceID": workspace_id,
                "AppID": agent_id
            }

            try:
                draft_response = self.api_client.make_request("GetAppConfigDraft", get_draft_body)
                existing_config = draft_response.get("AppConfigDraft", {})
                logger.info(f"获取到现有配置，将保留配置但替换知识库引用")

                # 如果源智能体有旧的知识库引用，记录并删除
                old_knowledge_ids = existing_config.get("KnowledgeIDs", [])
                if old_knowledge_ids:
                    logger.info(f"源智能体有旧知识库引用: {old_knowledge_ids}，将被删除")

            except Exception as e:
                logger.warning(f"获取现有配置失败，将使用默认配置: {str(e)}")
                existing_config = {}
                old_knowledge_ids = []

            # 在现有配置基础上添加/更新知识库配置
            if not existing_config:
                # 如果没有现有配置，使用默认配置
                app_config_draft = {
                    "ModelID": HiAgentConfig.DEFAULT_MODEL_ID,
                    "ModelConfig": {
                        "Temperature": 0.7,
                        "TopP": 0.9,
                        "MaxTokens": 2000,
                        "RoundsReserved": 10,
                        "RagNum": 5,
                        "Strategy": "react",
                        "MaxIterations": 5,
                        "RagEnabled": True,
                        "IsAdvancedMode": False,
                        "CurrentTimeEnabled": False,
                    },
                    "PrePrompt": f"你是{agent_name}。请严格根据知识库内容回答问题，不要回答知识库中不存在的内容。如果知识库中没有相关信息，请明确告知用户。"
                }
            else:
                # 使用现有配置
                app_config_draft = existing_config.copy()

                # 确保 ModelConfig 存在
                if "ModelConfig" not in app_config_draft:
                    app_config_draft["ModelConfig"] = {}

                # 启用 RAG
                app_config_draft["ModelConfig"]["RagEnabled"] = True

                # 如果没有 RagNum，设置默认值
                if "RagNum" not in app_config_draft["ModelConfig"]:
                    app_config_draft["ModelConfig"]["RagNum"] = 5

            # 完全替换知识库配置（删除旧的，使用新的）
            app_config_draft["KnowledgeIDs"] = [knowledge_id]  # 只包含新知识库
            app_config_draft["KnowledgeConfig"] = {
                "MatchType": "force",  # 强制只从知识库回答
                "TopK": 3,
                "RecallEmptyConfig": {
                    "Enabled": True,
                    "Text": "抱歉，我只能回答知识库中的相关问题。"
                }
            }

            logger.info(f"知识库配置已更新:")
            logger.info(f"  - 旧知识库引用: {old_knowledge_ids if old_knowledge_ids else '无'}")
            logger.info(f"  - 新知识库引用: [{knowledge_id}]")

            # 保存配置
            save_draft_body = {
                "WorkspaceID": workspace_id,
                "AppID": agent_id,
                "AppConfigDraft": app_config_draft
            }

            self.api_client.make_request("SaveAppConfigDraft", save_draft_body)
            logger.info(f"配置已保存，保留了源智能体的配置，替换为新知识库")

        except Exception as e:
            logger.error(f"Agent配置失败: {str(e)}")
            raise Exception(f"Agent配置失败: {str(e)}")

    def _cleanup_resources(
        self,
        agent_id: Optional[str] = None,
        knowledge_id: Optional[str] = None,
        workspace_id: Optional[str] = None
    ) -> None:
        """清理已创建的资源"""
        # workspace_id 必填，如果没有提供则记录错误并返回
        if not workspace_id:
            logger.error("Cannot cleanup resources: workspace_id is required")
            return

        if knowledge_id:
            try:
                self.api_client.make_request("DeleteDataset", {
                    "WorkspaceID": workspace_id,
                    "Id": knowledge_id
                })
                logger.info(f"知识库已删除 - ID: {knowledge_id}")
            except Exception as e:
                logger.error(f"知识库删除失败: {str(e)}")

        if agent_id:
            try:
                self.api_client.make_request("DeleteApp", {
                    "WorkspaceID": workspace_id,
                    "AppID": agent_id
                })
                logger.info(f"Agent已删除 - ID: {agent_id}")
            except Exception as e:
                logger.error(f"Agent删除失败: {str(e)}")
